<?php 
/**
  *聊天室服务器 WebSocket 专用
  **/
class WebServer{
      private $socket;
      private $accept = array();
      private $hands = array();

      function __construct($host,$port,$max){
            $this->socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
            socket_set_option($this->socket,SOL_SOCKET,SO_REUSEADDR,TRUE);
            socket_bind($this->socket,$host,$port);
            socket_listen($this->socket,$max);
            print_r($this->socket);
      }

      public function start(){
            while(true){
                  $cycle = $this->accept;
                  $cycle[] = $this->socket;
                  socket_select($cycle,$write,$except,null);
                  print_r($cycle);
                  foreach($cycle as $sock){
                      print_r((int)$sock);
                        if($sock == $this->socket){
                              $this->accept[] = socket_accept($sock);
                              $arr = array_keys($this->accept);
                              $key = end($arr);
                              $this->hands[$key] = false;
                        }else{
                              $length = socket_recv($sock,$buffer,204800,null);
                              $key = array_search($sock,$this->accept);
                              if(!$this->hands[$key]){
                                    $this->dohandshake($sock,$buffer,$key);
                              }else if($length < 1){
                                    $this->close($sock);
                              }else{
                                    //解码
                                    $data = $this->decode($buffer);
                                    print_r($data);
                                    //编码
                                    $data = $this->encode($data);
                                    print_r($data);
                                    //发送
                                    foreach($this->accept as $client){
                                          socket_write($client,$data,strlen($data));
                                    }
                              }
                        }
                        sleep(1);
                  }
            }            
      }
      
      /**
       * 首次与客户端握手
       */
      public function dohandshake($sock,$data,$key){
            if(preg_match("/Sec-WebSocket-Key:\s*(.*?)\r\n/",$data,$match)){
                  $response = base64_encode(sha1($match[1].'258EAFA5-E914-47DA-95CA-C5AB0DC85B11',true));
                  $upgrade = "HTTP/1.1 101 Switching Protocol\r\n".
                             "Upgrade: websocket\r\n".
                             "Connection: Upgrade\r\n".
                             "Sec-WebSocket-Accept: ".$response."\r\n\r\n";
                  echo $upgrade;
                  socket_write($sock,$upgrade,strlen($upgrade));
                  $this->hands[$key] = true;
            }
      }
      
      /**
       * 关闭一个客户端链接
       */
      public function close($sock){
            $key = array_search($sock,$this->accept);
            socket_close($sock);
            unset($this->accept[$key]);
            unset($this->hands[$key]);
      }

      public function decode($buffer){
            $len = $masks = $data = $decoded = null;
            $len = ord($buffer[1]) & 127;
            if($len === 126){
                  $masks = substr($buffer,4,4);
                  $data = substr($buffer,8);
            }else if($len === 127){
                  $masks = substr($buffer,10,4);
                  $data = substr($buffer,14);
            }else{
                  $masks = substr($buffer,2,4);
                  $data = substr($buffer,6);
            }
            for($index = 0;$index < strlen($data);$index++){
                  $decoded .= $data[$index] ^ $masks[$index%4];
            }
            return $decoded;
      }

      /**
       * 字符编码
       */
      public function encode($buffer){
            $length = strlen($buffer);
            if($length <= 125){
                  return "\x81".chr($length).$buffer;
            }else if($length <= 65535){
                  return "\x81".chr(126).pack("n",$length).$buffer;
            }else{
                  return "\x81".char(127).pack("xxxxN",$length).$buffer;
            }
      }
}

$server_socket = new WebServer("192.168.10.134",8008,1000);
$server_socket->start();
